import { message } from 'ant-design-vue'
import { fabric } from 'fabric'

import { DmpImgPaintOptions, MarkInfo, MarkInfoRect, MarkObj, PaintResizeOptions } from '../types/dmp-paint'
import { createText } from '../utils/text'

enum ERROR_MSG {
  CANVAS_NOT_INIT = '画布未加载',
  IMAGE_NOT_INIT = '图片未加载'
}

/**
 *  标注-绘画基类
 */
export class DmpImgBasicPaint {
  /**
   * canvas挂载的dom
   */
  dom: HTMLCanvasElement | null
  /**
   * fabric canvas实例
   */
  canvas: fabric.Canvas | null
  /**
   * 图片实例
   */
  image: fabric.Image | null
  /**
   * 图片缩放比例
   */
  imgScale: number
  /**
   * 拖拽对象信息
   */
  draggingObj: {
    x: number
    y: number
  }
  /**
   * 标注对象列表
   */
  markObjList: fabric.Object[]

  constructor(options?: DmpImgPaintOptions) {
    console.log('options', options)

    this.dom = null
    this.canvas = null
    this.image = null
    this.imgScale = 1
    this.draggingObj = {
      x: 0,
      y: 0
    }
    this.markObjList = []
  }

  /**
   * 初始化
   * @param dom canvas挂在的dom
   */
  init(dom: HTMLCanvasElement) {
    this.dom = dom

    // 创建画布
    this.canvas = new fabric.Canvas(dom, {
      // 启用右键，button的数字为3
      fireRightClick: true,
      // 禁止默认右键菜单
      stopContextMenu: true
    })

    this.onEvent()
  }

  /**
   * 监听画布各种事件
   */
  onEvent() {
    if (this.canvas === null) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }

    this.canvas.on('mouse:down', e => {
      console.log('mouse:down', e)
    })
    this.canvas.on('mouse:move', e => {
      console.log('mouse:move', e)
    })
    this.canvas.on('mouse:up', e => {
      console.log('mouse:up', e)
    })
    // 监听鼠标移入事件
    this.canvas.on('mouse:over', () => {})
    // 监听鼠标移出事件
    this.canvas.on('mouse:out', () => {})
    // 监听鼠标滚动事件
    this.canvas.on('mouse:wheel', e => {
      console.log(e)
    })
    this.canvas.on('object:removed', () => {})
    this.canvas.on('object:modified', e => {
      console.log(e)
    })
    // 元素改变大小
    this.canvas.on('object:scaling', () => {})
    this.canvas.on('object:moving', () => {})
    //选中图形
    this.canvas.on('selection:created', e => {
      console.log(e)
    })
    //选中图形切换
    this.canvas.on('selection:updated', e => {
      console.log(e)
    })

    this.canvas.on('selection:cleared', () => {})
  }

  /**
   * 改变canvas画布大小
   */
  resizeCanvas(options: PaintResizeOptions) {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }

    if (options.w) {
      this.canvas.setWidth(options.w)
    }
    if (options.h) {
      this.canvas.setHeight(options.h)
    }
  }

  /**
   * 渲染画布
   * @returns 渲染画布
   */
  renderAll() {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }
    this.canvas.renderAll()
  }

  /**
   * 加载图片
   */
  loadImage(url: string) {
    return new Promise((rs, rj) => {
      fabric.Image.fromURL(url, image => {
        if (!this.canvas) {
          rj(ERROR_MSG.CANVAS_NOT_INIT)
          return
        }

        this.image = image

        if (!this.image.width || !this.image.height) {
          rj('图片加载失败')
          return
        }

        // 判断长短边，按照短边缩放
        this.imgScale = Math.min(this.canvas.getWidth() / this.image.width, this.canvas.getHeight() / this.image.height)
        this.image.scale(this.imgScale)

        this.image.set({
          // 禁止显示控制角
          hasControls: false,
          selectable: false,
          evented: false,
          type: 'image'
        })
        // 将图片添加到画布
        this.canvas.add(this.image)
        // 使图片居中
        this.canvas.centerObject(this.image)
        // 渲染画布
        this.canvas.renderAll()

        fabric.util.requestAnimFrame(() => {
          console.log(`图片加载完成`, this.image)
          rs(true)
        })
      })
    })
  }

  /**
   * @returns 图片是否初始化完成
   */
  isImageInitOk(): boolean {
    return (
      this.image !== null &&
      this.image.width !== undefined &&
      this.image.height !== undefined &&
      this.image.top !== undefined &&
      this.image.left !== undefined
    )
  }

  /**
   * 将标注对象绘制到画布
   * @returns
   */
  drawObjectToCanvas(info: MarkInfo) {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }

    if (this.isImageInitOk() === false) {
      message.error(ERROR_MSG.IMAGE_NOT_INIT)
      return
    }

    if (info.type === 'rect') {
      this.drawRect(info)
    }
  }

  drawRect(info: MarkInfoRect) {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }

    if (this.isImageInitOk() === false) {
      message.error(ERROR_MSG.IMAGE_NOT_INIT)
      return
    }

    const imageLeft = this.image!.left || 0
    const imageTop = this.image!.top || 0

    const points = info.points.map(item => ({
      x: item.x * this.imgScale + imageLeft,
      y: item.y * this.imgScale + imageTop
    }))

    const rect = new fabric.Rect({
      // @ts-ignore
      uid: info.uid,
      left: points[0].x,
      top: points[0].y,
      width: points[1].x - points[0].x,
      height: points[1].y - points[0].y,
      fill: 'rgba(24, 104, 233, 0.1)',
      stroke: info.color,
      strokeWidth: 2
      // selectable: true
    }) as MarkObj

    console.log('rect', rect)

    this.canvas.add(rect)
    // this.setMarkTagText(rect, 'rect1')
    this.markObjList.push(rect)
  }

  /**
   * 将图形文字写入图形
   * @returns
   */
  setMarkTagText(markObj: MarkObj, str: string) {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }

    // 获取矩形中心点坐标
    const centerPoint = markObj.getCenterPoint()
    // TODO:暂未封装多边形，所以先注释// 多边形取中心值是参照left和right，会有问题，需要特殊处理
    // if (markObj.type === 'polygon') {
    //   const point = calculatePolygonCenter(markObj as fabric.Polygon)
    //   centerPoint.x = point.x
    //   centerPoint.y = point.y
    // }

    // 创建 IText 对象
    const text = createText(str)

    text.set({
      left: centerPoint.x - text.width! / 2,
      top: centerPoint.y - text.height! / 2,
      // @ts-ignore 标注对象id，方便删除
      markObjId: markObj.uid
    })

    markObj.on('moving', function () {
      const centerPoint = markObj!.getCenterPoint()
      text.set({
        left: centerPoint.x - text.width! / 2,
        top: centerPoint.y - text.height! / 2
      })
    })
    markObj.on('modified', function () {
      const centerPoint = markObj!.getCenterPoint()
      text.set({
        left: centerPoint.x - text.width! / 2,
        top: centerPoint.y - text.height! / 2
      })
    })
    markObj.on('removed', () => {
      if (!this.canvas) {
        message.error(ERROR_MSG.CANVAS_NOT_INIT)
        return
      }
      this.canvas.remove(text)
    })
    text.sendToBack()
    this.canvas.add(text)
    return text
  }

  /**
   * 清空画布
   */
  clearCanvas() {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }
    this.canvas.clear()
  }

  /**
   * 清空标注对象
   */
  clearMarkObjList() {
    if (!this.canvas) {
      message.error(ERROR_MSG.CANVAS_NOT_INIT)
      return
    }

    this.markObjList.forEach(item => {
      this.canvas!.remove(item)
    })
    this.markObjList = []
  }
}
